package com.multitrack.util;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;

import android.os.Handler;
import android.os.Message;

import com.multitrack.datatype.CurrLocationList;
import com.multitrack.datatype.Event;
import com.multitrack.datatype.GPSList;
import com.multitrack.datatype.IdentityList;
import com.multitrack.datatype.MemberGPS;
import com.multitrack.datatype.STATE;
import com.multitrack.datatype.SocketMessage;

public class CommunicationManager extends Thread {

	static final String host = "14.63.225.150";
	// DEFAULT
	// static final int port = 1203;
	// BBJ
	// static final int port = 1203;
	// GJH
	static final int port = 1205;

	private SocketAddress address;
	private Socket socket;
	private int connTimeout;
	private int readTimeout;

	private Handler mHandler;
	private SocketMessage message;

	private ObjectInputStream in;
	private ObjectOutputStream out;

	private Object object;
	private Object resultObject;
	private Exception exception;

	private SocketMessage resultMessage;

	private int state;
	private final int NULL = 0;
	private Message msg;

	public CommunicationManager() {
		this.connTimeout = 30000;
		this.readTimeout = 30000;
	}

	public CommunicationManager(Handler mHandler) {
		this.connTimeout = 30000;
		this.readTimeout = 30000;
		this.mHandler = mHandler;
	}

	@Override
	public void run() {
		address = new InetSocketAddress(host, port);
		socket = new Socket();

		switch (message) {
		// /////////////////////////////////////////////////////////////////////
		// EventActivity.java
		// /////////////////////////////////////////////////////////////////////
		case EVENT_QUIT:
			writeTwoReadOne();
			break;

		case EVENT_JOIN:
			writeTwoReadOne();
			break;

		case CREATE_EVENT:
			writeTwoReadOne();
			break;

		case IS_IN_EVENT:
			writeTwoReadOne();
			break;

		case CURR_LOCATION:
			writeTwoReadOne();
			break;

		case RECORD_LOCATION:
			writeTwoReadOne();
			break;

		case REQUEST_ALL_MEMBER_CURRENT_LOCATION:
			writeTwoReadOne();
			break;

		case REQUEST_EVENT_INFO:
			writeTwoReadOne();
			break;

		case REQUEST_EVENT_LIST:
			writeOneReadOne();
			break;

		case REQUEST_MEMBER_LIST:
			writeTwoReadOne();
			break;

		case REQUEST_MEMBER_TRACK:
		case REQUEST_MEMBER_TRACK_MOVE:
			writeTwoReadOne();
			break;

		case SEND_DESTINATION:
			writeTwoReadOne();
			break;

		case CHANGE_LEADER:
			writeTwoReadOne();
			break;

		case BAN_MEMBER:
			writeTwoReadOne();
			break;

		// /////////////////////////////////////////////////////////////////////
		// JoinActivity.java
		// /////////////////////////////////////////////////////////////////////
		case APP_JOIN:
			requestJoinApp();
			break;
		// /////////////////////////////////////////////////////////////////////
		// IntroActivity.java
		// /////////////////////////////////////////////////////////////////////
		case IS_MEMBER:
			requestCheckAppMember();
			break;

		default:
			break;
		}
	}

	private void writeOneReadOne() {
		try {
			socket.connect(address, readTimeout);
			socket.setSoTimeout(connTimeout);

			out = new ObjectOutputStream(socket.getOutputStream());
			in = new ObjectInputStream(socket.getInputStream());

			out.writeObject(message);
			out.flush();

			resultObject = in.readObject();

		} catch (SocketTimeoutException time) {
			exception = time;
		} catch (IOException e) {
			exception = e;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		try {
			closeAll();
		} catch (IOException e) {
			e.printStackTrace();
		}

		state = STATE.findException(exception);

		msg = mHandler.obtainMessage(state, message.ordinal(), NULL,
				resultObject);
		mHandler.sendMessage(msg);

		ThreadManager.remove(currentThread());
	}

	private void writeTwoReadOne() {
		try {
			socket.connect(address, readTimeout);
			socket.setSoTimeout(connTimeout);

			out = new ObjectOutputStream(socket.getOutputStream());
			in = new ObjectInputStream(socket.getInputStream());

			out.writeObject(message);
			out.flush();

			// eventId
			out.writeObject(object);
			out.flush();

			resultObject = in.readObject();

		} catch (SocketTimeoutException e) {
			exception = e;
		} catch (IOException e) {
			exception = e;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		try {
			closeAll();
		} catch (IOException e) {
			e.printStackTrace();
		}

		state = STATE.findException(exception);

		msg = mHandler.obtainMessage(state, message.ordinal(), NULL,
				resultObject);
		mHandler.sendMessage(msg);

		ThreadManager.remove(currentThread());
	}

	/*
	 * 앱에 사용자를 등록합니다.
	 */
	private void requestJoinApp() {
		try {
			socket.connect(address, readTimeout);
			socket.setSoTimeout(connTimeout);

			out = new ObjectOutputStream(socket.getOutputStream());
			in = new ObjectInputStream(socket.getInputStream());

			out.writeObject(message);
			out.flush();

			out.writeObject(object);
			out.flush();

			resultMessage = (SocketMessage) in.readObject();

		} catch (SocketTimeoutException time) {
			exception = time;
		} catch (IOException e) {
			exception = e;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		try {
			closeAll();
		} catch (IOException e) {
			e.printStackTrace();
		}

		state = STATE.findException(exception);

		msg = mHandler.obtainMessage(state, resultMessage);
		mHandler.sendMessage(msg);

		ThreadManager.remove(currentThread());

	}

	/*
	 * 
	 */
	private void requestCheckAppMember() {

		try {
			socket.connect(address, readTimeout);
			socket.setSoTimeout(connTimeout);

			out = new ObjectOutputStream(socket.getOutputStream());
			in = new ObjectInputStream(socket.getInputStream());

			out.writeObject(message);
			out.flush();

			out.writeObject(object);
			out.flush();

			resultMessage = (SocketMessage) in.readObject();

		} catch (SocketTimeoutException time) {
			exception = time;
		} catch (IOException e) {
			exception = e;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		try {
			closeAll();
		} catch (IOException e) {
			e.printStackTrace();
		}

		state = STATE.findException(exception);

		while (ThreadManager.size() > 1) {
			;
		}

		msg = mHandler.obtainMessage(state, resultMessage);
		mHandler.sendMessage(msg);

		ThreadManager.remove(currentThread());

	}

	/*
	 * 메소드 부분
	 */
	private void closeAll() throws IOException {
		if (in != null)
			in.close();
		if (out != null)
			out.close();
		if (socket != null)
			socket.close();
	}

	public void setObj(Object obj) {
		this.object = obj;
	}

	public void setReadStreamTimeout(int readTimeout) {
		if (readTimeout < 0) {
			this.readTimeout = 0;
		} else {
			this.readTimeout = readTimeout;
		}
	}

	public void setConnectionTimeout(int connTimeout) {
		if (connTimeout < 0) {
			this.connTimeout = 0;
		} else {
			this.connTimeout = connTimeout;
		}
	}

	public void setMessage(SocketMessage message) {
		this.message = message;
	}

	public void setHanlder(Handler mHandler) {
		this.mHandler = mHandler;
	}

}
